package com.quxiang.pay.service;

import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.quxiang.pay.constant.Constant;
import com.quxiang.pay.dao.CymjDao;
import com.quxiang.pay.dao.MaqueDao;
import com.quxiang.pay.dao.XunLeDao;
import com.quxiang.pay.model.AccessTokenModel;
import com.quxiang.pay.model.OrderResponseModel;
import com.quxiang.pay.model.PayCallbackModel;
import com.quxiang.pay.model.PayModel;
import com.quxiang.pay.model.PayOrderModel;
import com.quxiang.pay.model.ProductModel;
import com.quxiang.pay.model.ResponseModel;
import com.quxiang.pay.model.WxUserInfo;
import com.quxiang.pay.util.ConfigUtils;
import com.quxiang.pay.util.EncryptUtil;
import com.quxiang.pay.util.HttpClientUtils;

@Service
public class PayServiceImpl implements PayService {

	private final Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);

	private final java.text.DecimalFormat df = new java.text.DecimalFormat("0");

	private final XmlMapper xmlMapper = new XmlMapper();
	private final ObjectMapper objectMapper = new ObjectMapper();

	@Autowired
	private CymjDao cymjDao;

	@Autowired
	private XunLeDao xunleDao;

	@Autowired
	private MaqueDao maqueDao;

	@Autowired
	private WechatService wechatService;

	@Autowired
	private UserService userService;

	// 判断产品是否存在
	private int checkProduct(ProductModel product) {

		if (product.getProductType() == Constant.TYPE_CYMJ) {
			return cymjDao.getOneInfo("payOrder.checkProduct", product);
		} else if (product.getProductType() == 2) {
			return xunleDao.getOneInfo("payOrder.checkProduct", product);
		} else if (product.getProductType() == 3) {
			return maqueDao.getOneInfo("payOrder.checkProduct", product);
		} else {
			return 0;
		}

	}

	private int getOrderId() {
		PayOrderModel order = new PayOrderModel();
		cymjDao.getOneInfo("payOrder.getOrderId", order);

		return order.getOrderId();

	}

	// 订单入库
	public int createOrder(PayOrderModel payOrder, int productType) {

		if (productType == Constant.TYPE_CYMJ) {
			return cymjDao.insert("payOrder.insertOrder", payOrder);

		} else if (productType == Constant.TYPE_XUNLE) {
			return xunleDao.insert("payOrder.insertOrder", payOrder);

		} else if (productType == 3) {
			return maqueDao.insert("payOrder.insertOrder", payOrder);
		} else {
			return 0;
		}

	}

	private WxUserInfo getWxUserInfo(String orderCode, int productType) {

		WxUserInfo userInfo = new WxUserInfo();
		Map<String, String> wxInfo = null;
		if (productType == Constant.TYPE_CYMJ) {
			wxInfo = cymjDao.getOneInfo("payOrder.selectByCode", orderCode);
		} else if (productType == 2) {
			wxInfo = xunleDao.getOneInfo("payOrder.selectByCode", orderCode);
		} else if (productType == 3) {
			wxInfo = maqueDao.getOneInfo("payOrder.selectByCode", orderCode);
		}
		if (wxInfo != null && wxInfo.size() > 0) {
			userInfo.setOpenid(wxInfo.get("orderOpenId"));
			userInfo.setUnionid(wxInfo.get("orderUnionId"));
			logger.info("微信信息已经获取.. {}", wxInfo);
			return userInfo;
		}

		AccessTokenModel accessToken = wechatService.accessToken(orderCode);
		if (accessToken == null || StringUtils.isNotEmpty(accessToken.getErrcode())) {
			logger.warn("生成支付订单:获取微信Token失败， accessToken = {} ", ToStringBuilder.reflectionToString(accessToken));
			return null;
		}
		if (StringUtils.isNotEmpty(accessToken.getUnionid())) {

			userInfo.setOpenid(accessToken.getOpenid());
			userInfo.setUnionid(accessToken.getUnionid());
			logger.info("unionid 在accessToken中已经存在，直接使用");
			//return userInfo;
		} else {

			userInfo = wechatService.getUserInfo(accessToken.getAccess_token(), accessToken.getOpenid());
		}
		
		if (userInfo != null) {
			userInfo.setLanguage(orderCode);
			// 微信数据插入数据库
			if (productType == Constant.TYPE_CYMJ) {
				cymjDao.insert("user.insertWxUser", userInfo);
			} else if (productType == 2) {
				xunleDao.insert("user.insertWxUser", userInfo);
			} else if (productType == 3) {
				maqueDao.insert("user.insertWxUser", userInfo);
			}
		}

		return userInfo;

	}

	/***
	 * 1.验证商品信息 2.获取用户信息 3.判断用户是否存在 4.生成支付订单
	 */
	@Override
	public int makePayOrder(ProductModel product, ResponseModel<PayModel> response, String ip) {

		int result = 1;
		// 金额数据看存储*1000000
		product.setProductPrice(product.getProductPrice().multiply(new BigDecimal(1000000)));
		result = checkProduct(product);
		if (result == 0) {
			response.setInfo(6, "产品不存在");
			logger.warn("生成支付订单:产品不存在  ");
			return 6;
		}

		// 将code存入订单里面，如果有相同的code直接获取 用户微信数据

		WxUserInfo wxUserInfo = getWxUserInfo(product.getWxCode(), product.getProductType());

		if (wxUserInfo == null || StringUtils.isNotEmpty(wxUserInfo.getErrcode())) {
			response.setInfo(7, "获取微信信息失败，请重新进入商品页面");
			logger.warn("生成支付订单:获取微信信息失败  {}", ToStringBuilder.reflectionToString(wxUserInfo));
			return 7;
		}

		result = userService.hasAgent(wxUserInfo.getUnionid(), product.getProductType());

		if (result == 1) {
			response.setInfo(8, "游戏用户不存在");
			logger.warn("生成支付订单:游戏用户不存在");
			return 8;
		} else if (result == 2) {
			response.setInfo(8, "请先前往游戏中心绑定邀请");
			logger.warn("生成支付订单:代理不存在 请先前往游戏中心绑定邀请");
			return 8;
		}

		// 发起订单提交
		PayOrderModel payOrder = new PayOrderModel();
		SortedMap<String, String> paramMap = makeParam(wxUserInfo.getOpenid(), product.getProductPrice(), ip,
				payOrder, product.getProductType());
		String sign = EncryptUtil.createSign("UTF-8", paramMap, ConfigUtils.pay_key);
		paramMap.put("sign", sign);

		OrderResponseModel resp = sendHttp(paramMap);
		if (resp == null || !"0".equals(resp.getStatus()) || !"0".equals(resp.getResult_code())) {
			String msg = "下单 resp 为 null";
			if (resp != null) {
				msg = resp.getStatus() + "--" + resp.getErr_code() + resp.getErr_msg() + resp.getMessage();
			}
			logger.info("提交支付订单 失败 status = {} ，errocode = {}，errooMsg = {} ", resp.getStatus(), msg);
			response.setInfo(9, "提交订单失败，请稍后再试");

			// 数据库生成失败订单数据
			// payOrder.setOrderTokenId(resp.getToken_id());
			payOrder.setOrderUnionId(wxUserInfo.getUnionid());
			payOrder.setOrderStatus(3);// 发送失败
			payOrder.setOrderGems(product.getGems());
			payOrder.setOrderCode(product.getWxCode());
			payOrder.setOrderErrorMsg("下单失败 ：" + msg);
			// 插入数据库
			result = createOrder(payOrder, product.getProductType());

			return 9;

		} else {
			// 数据库生成订单数据
			payOrder.setOrderTokenId(resp.getToken_id());
			payOrder.setOrderUnionId(wxUserInfo.getUnionid());
			payOrder.setOrderStatus(1);// 已发送状态
			payOrder.setOrderGems(product.getGems());
			payOrder.setOrderCode(product.getWxCode());
			payOrder.setOrderErrorMsg("下单成功");
			// 插入数据库
			result = createOrder(payOrder, product.getProductType());
			if (result != 0) {
				response.setInfo(0, "成功");
				String payInfo = resp.getPay_info();
				PayModel readValue = null;
				try {
					readValue = objectMapper.readValue(payInfo, PayModel.class);
				} catch (Exception e) {
					logger.error("解析error  e = {}", e);

				}
				readValue.setOrderId(payOrder.getOrderId());
				response.setData(readValue);
				return 0;
			} else {
				response.setInfo(11, "生成订单失败，请稍后再试");
				return 11;
			}
		}
	}

	private OrderResponseModel sendHttp(SortedMap<String, String> prams) {

		try {
			String xml = makeRequestBody(prams);
			// logger.info("提交支付订单 xml = {} ", xml);
			String result = HttpClientUtils.postXml(ConfigUtils.pay_make_order, xml);
			if (StringUtils.isNotEmpty(result)) {
				OrderResponseModel res = xmlMapper.readValue(result, OrderResponseModel.class);
				return res;
			}

		} catch (Exception e) {
			logger.error("send pay error {}", e);
		}
		return null;
	}

	// http请求提交订单
	private SortedMap<String, String> makeParam(String opendId, BigDecimal productPrice, String ip,
			PayOrderModel payOrder, int productType) {
		SortedMap<String, String> pramMap = new TreeMap<String, String>();
		pramMap.put("service", "pay.weixin.jspay");
		// pramMap.put("version", "2.0");
		// pramMap.put("charset", "UTF-8");
		// pramMap.put("sign_type", "MD5");
		pramMap.put("mch_id", ConfigUtils.pay_mch_id);
		pramMap.put("is_raw", "1");
		// pramMap.put("is_minipg", "0");
		int orderId = getOrderId();
		pramMap.put("out_trade_no", String.valueOf(orderId));// 商户订单号
		payOrder.setOrderId(orderId);
		pramMap.put("body", "房卡购买");
		pramMap.put("sub_openid", opendId);
		payOrder.setOrderOpenId(opendId);
		pramMap.put("sub_appid", ConfigUtils.wx_appid);
		BigDecimal total = productPrice.divide(new BigDecimal(10000)); // 单位分
		pramMap.put("total_fee", df.format(total));// 充值金额 单位为分
		payOrder.setOrderFee(productPrice);
		pramMap.put("mch_create_ip", ip);
		if (productType == Constant.TYPE_CYMJ) {
			pramMap.put("notify_url", ConfigUtils.pay_cburl + "/cymjcallback");// 成功通知地址
		} else if (productType == 2) {
			pramMap.put("notify_url", ConfigUtils.pay_cburl + "/xunlecallback");// 成功通知地址
		} else if (productType == 3) {
			pramMap.put("notify_url", ConfigUtils.pay_cburl + "/maquecallback");// 成功通知地址
		}

		pramMap.put("nonce_str", String.valueOf(System.currentTimeMillis()));
		return pramMap;
	}

	// 生成xml
	private String makeRequestBody(SortedMap<String, String> payParams) {

		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		Set<Entry<String, String>> es = payParams.entrySet();
		Iterator<Entry<String, String>> it = es.iterator();
		while (it.hasNext()) {
			Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"appkey".equals(k)) {
				sb.append("<" + k + ">" + payParams.get(k) + "</" + k + ">\n");
			}
		}
		sb.append("</xml>");
		return sb.toString();

	}

	@Override
	public int checkOrderParams(ProductModel product, ResponseModel<PayModel> response) {
		int result = 0;

		if (product == null) {
			response.setInfo(1, "参数不存在:产品信息");
			return 1;
		}
		if (StringUtils.isEmpty(product.getProductCode())) {

			response.setInfo(2, "产品为空");
			logger.warn("生成支付订单:产品为空");
			return 2;
		}

		if (product.getGems() == 0) {
			response.setInfo(3, "房卡数为空");
			logger.warn("生成支付订单:房卡数为空");
			return 3;
		}

		if (product.getProductPrice() == null) {
			response.setInfo(4, "产品金额为空");
			logger.warn("生成支付订单:产品金额为空");
			return 4;
		}

		if (StringUtils.isEmpty(product.getWxCode())) {
			response.setInfo(5, "微信验证码为空");
			logger.warn("生成支付订单:微信验证码为空");
			return 5;
		}

		if (product.getProductType() != Constant.TYPE_CYMJ && product.getProductType() != Constant.TYPE_XUNLE
				&& product.getProductType() != 3) {
			response.setInfo(4, "产品类型不存在");
			logger.warn("生成支付订单:产品类型不存在");
			return 4;
		}

		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class, value = "cymj_transactionManager")
	public int doCallbackCymj(PayCallbackModel payCallback) throws Exception {
		// try {
		// 1.检验参数是否存在
		logger.info("充值回调 content = {}", ToStringBuilder.reflectionToString(payCallback));
		if (!"0".equals(payCallback.getStatus()) || !"0".equals(payCallback.getResult_code())) {
			logger.warn("订单通知返回:状态异常");
			return 1;
		}
		int status = payCallback.getPay_result();
		if (status == 0) {
			logger.info("充值回调成功");
		} else {
			logger.info("充值回调失败 {} -- {}", payCallback.getErr_msg(), payCallback.getMessage());
		}

		PayOrderModel model = new PayOrderModel(payCallback);
		return updateCymj(model);

	}

	@Transactional(rollbackFor = Exception.class, value = "cymj_transactionManager")
	public int updateCymj(PayOrderModel model) throws Exception {

		int result = 0;
		Map<String, Object> order = cymjDao.getOneInfo("payOrder.getOrderInfoCallback", model);
		if (order == null || order.size() == 0) {
			logger.info("充值回调 订单不存在..");
			return 0;
		}
		if (1 != (Integer) order.get("order_status")) {
			logger.info("充值回调 订单 已经修改 status = {} ", order.get("order_status"));
			return 0;
		}
		// 更新订单状态
		result = cymjDao.update("payOrder.updateOrder", model);
		if (result == 1) {
			// 更新房卡
			result = cymjDao.update("payOrder.updateUserGems", order);

			if (result == 0) {
				logger.info("充值回调 更新房卡失败");
				// 回滚数据
				throw new RuntimeException("充值回调 更新房卡失败");
			} else {
				return 0;
			}
		} else {
			logger.info("充值回调 修改订单失败 update count ={}", result);
			return -1;
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class, value = "xunle_transactionManager")
	public int doCallbackXunle(PayCallbackModel payCallback) throws Exception {
		// try {
		// 1.检验参数是否存在
		logger.info("充值回调 content = {}", ToStringBuilder.reflectionToString(payCallback));
		if (!"0".equals(payCallback.getStatus()) || !"0".equals(payCallback.getResult_code())) {
			logger.warn("订单通知返回:状态异常");
			return 1;
		}
		int status = payCallback.getPay_result();
		if (status == 0) {
			logger.info("充值回调成功");
		} else {
			logger.info("充值回调失败 {} -- {}", payCallback.getErr_msg(), payCallback.getMessage());
		}

		PayOrderModel model = new PayOrderModel(payCallback);
		return updateXunle(model);

	}

	@Transactional(rollbackFor = Exception.class, value = "xunle_transactionManager")
	public int updateXunle(PayOrderModel model) {

		int result = 0;
		Map<String, String> order = xunleDao.getOneInfo("payOrder.getOrderInfoCallback", model);
		if (order == null || order.size() == 0) {
			logger.info("充值回调 订单不存在..");
			return 0;
		}

		if (!"1".equals(order.get("status"))) {
			logger.info("充值回调 订单 已经修改 status = {} ", order.get("status"));
			return 0;
		}
		// 更新订单状态
		result = xunleDao.update("payOrder.updateOrder", model);
		if (result == 1) {
			// 更新房卡
			result = xunleDao.update("payOrder.updateUserGems", order);
			if (result == 0) {
				logger.info("充值回调 更新房卡失败");
				// 回滚数据
				throw new RuntimeException("充值回调 更新房卡失败");
			} else {
				return 0;
			}
		} else {
			logger.info("充值回调 修改订单失败");
			return -1;
		}
	}

	@Override
	public int userCancel(int orderId) {
		// 更新订单状态
		int result = 0;
		PayOrderModel model = new PayOrderModel();
		model.setOrderId(orderId);
		model.setOrderErrorMsg("用户取消付款");
		model.setOrderStatus(3);
		result = cymjDao.update("payOrder.userCancle", model);
		if (result == 0) {
			result = xunleDao.update("payOrder.userCancle", model);
			if (result == 0) {
				result = maqueDao.update("payOrder.userCancle", model);
			}
		}

		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class, value = "maque_transactionManager")
	public int doCallbackMaque(PayCallbackModel payCallback) throws Exception {
		// try {
		// 1.检验参数是否存在
		logger.info("充值回调 content = {}", ToStringBuilder.reflectionToString(payCallback));
		if (!"0".equals(payCallback.getStatus()) || !"0".equals(payCallback.getResult_code())) {
			logger.warn("订单通知返回:状态异常");
			return 1;
		}
		int status = payCallback.getPay_result();
		if (status == 0) {
			logger.info("充值回调成功");
		} else {
			logger.info("充值回调失败 {} -- {}", payCallback.getErr_msg(), payCallback.getMessage());
		}

		PayOrderModel model = new PayOrderModel(payCallback);
		return updateMaque(model);

	}

	@Transactional(rollbackFor = Exception.class, value = "maque_transactionManager")
	public int updateMaque(PayOrderModel model) throws Exception {

		int result = 0;
		Map<String, Object> order = maqueDao.getOneInfo("payOrder.getOrderInfoCallback", model);
		if (order == null || order.size() == 0) {
			logger.info("充值回调 订单不存在..");
			return 0;
		}
		if (1 != (Integer) order.get("order_status")) {
			logger.info("充值回调 订单 已经修改 status = {} ", order.get("order_status"));
			return 0;
		}
		// 更新订单状态
		result = maqueDao.update("payOrder.updateOrder", model);
		if (result == 1) {
			// 更新房卡
			result = maqueDao.update("payOrder.updateUserGems", order);

			if (result == 0) {
				logger.info("充值回调 更新房卡失败");
				// 回滚数据
				throw new RuntimeException("充值回调 更新房卡失败");
			} else {
				return 0;
			}
		} else {
			logger.info("充值回调 修改订单失败 update count ={}", result);
			return -1;
		}
	}

}
